package com.xuecheng.manage_cms.service;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsSite;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.domain.cms.response.CmsPageResult;
import com.xuecheng.framework.domain.cms.response.CmsPostPageResult;
import com.xuecheng.framework.domain.cms.response.QueryResponseResult;
import com.xuecheng.framework.enums.PageTypeEnum;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResult;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.framework.utils.PageUtils;
import com.xuecheng.manage_cms.config.RabbitmqConfig;
import com.xuecheng.manage_cms.dao.CmsMongoDbDao;
import com.xuecheng.manage_cms.dao.SiteMongoDbDao;
import com.xuecheng.manage_cms.dao.TemplateMongoDbDao;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 * @version 1.0
 * @create 2018-09-12 18:32
 **/
@Service
public class PageService {

    @Autowired
    private CmsMongoDbDao cmsMongoDbDao;

    @Autowired
    private SiteMongoDbDao siteMongoDbDao;

    @Autowired
    private TemplateMongoDbDao templateMongoDbDao;

    @Autowired
    GridFsTemplate gridFsTemplate;

    @Autowired
    GridFSBucket gridFSBucket;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 页面查询方法
     * @param page 页码，从1开始记数
     * @param size 每页记录数
     * @param queryPageRequest 查询条件
     * @return
     */
    public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest){
        if (page<1){
            page = 1;
        }
        if (size<1){
            size = 1;
        }
        CmsPage cmsPage = new CmsPage();
        BeanUtils.copyProperties(queryPageRequest,cmsPage);
        Sort sort = new Sort(Sort.Direction.DESC, "pageCreateTime");
        List<CmsPage> cmsPages = cmsMongoDbDao.queryListWhithSort(cmsPage,sort);
        //格式化
        formatList(cmsPages);
        PageInfo<CmsPage> pageInfo = new PageUtils<CmsPage>().getPageList(cmsPages, page, size);
        QueryResult<CmsPage> queryResult = new QueryResult<>();
        queryResult.setList(pageInfo.getList());
        queryResult.setTotal(pageInfo.getTotal());
        return new QueryResponseResult(CommonCode.SUCCESS,queryResult);

        /*Sort sort = new Sort(Sort.Direction.DESC, "pageCreateTime");
        List<CmsPage> pageList = cmsMongoDbDao.getPageWithSort(cmsPage,page,size,sort);
        Long total = cmsMongoDbDao.getCount(cmsPage);
        QueryResult<CmsPage> queryResult = new QueryResult<>();
        queryResult.setList(pageList);
        queryResult.setTotal(total);
        QueryResponseResult result = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
        return result;*/

        /*PageHelper.startPage(page,size);
        Sort sort = new Sort(Sort.Direction.DESC, "pageCreateTime");
        List<CmsPage> cmsPages = cmsMongoDbDao.queryListWhithSort(cmsPage,sort);
        PageInfo pageInfo = new PageInfo(cmsPages);
        QueryResult<CmsPage> queryResult = new QueryResult<>();
        queryResult.setList(pageInfo.getList());
        queryResult.setTotal(pageInfo.getTotal());
        return new QueryResponseResult(CommonCode.SUCCESS,queryResult);*/
    }

    /**
     * @Description 格式化列表数据
     * @author ShengJinFeng
     * @date 2020/1/19
     */
    private void formatList(List<CmsPage> cmsPages) {
        cmsPages.stream().forEach(cms -> {
            if (StringUtils.isNotBlank(cms.getPageType())){
                if (StringUtils.equals(cms.getPageType(), PageTypeEnum.STATIC_STATE.getKey())){
                    cms.setPageType(PageTypeEnum.STATIC_STATE.getValue());
                }else{
                    cms.setPageType(PageTypeEnum.DYNAMIC_STATE.getValue());
                }
            }
        });
    }

    /**
     * @Description 查询站点列表
     * @author ShengJinFeng
     * @date 2020/1/16
     */
    public QueryResponseResult findSiteList() {
        List<CmsSite> siteList = siteMongoDbDao.queryList(new CmsSite());
        QueryResult<CmsSite> queryResult = new QueryResult<>();
        queryResult.setList(siteList);
        return new QueryResponseResult(CommonCode.SUCCESS,queryResult);
    }

    /**
     * @Description 添加页面
     * @author ShengJinFeng
     * @date 2020/1/16
     */
    public CmsPageResult add(CmsPage cmsPage) {
        if (cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_ADDPAGE_INVALID);
        }
        CmsPage recode = new CmsPage();
        recode.setPageName(cmsPage.getPageName());
        recode.setSiteId(cmsPage.getSiteId());
        recode.setPageWebPath(cmsPage.getPageWebPath());
        //校验页面唯一性
        CmsPage page = cmsMongoDbDao.queryOne(recode);
        if (page != null){
            ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
        }
        cmsPage.setPageId(null);
        cmsPage.setPageCreateTime(new Date());
        cmsMongoDbDao.save(cmsPage);
        return new CmsPageResult(CommonCode.SUCCESS,cmsPage);

    }

    /**
     * @Description 查询站点列表
     * @author ShengJinFeng
     * @date 2020/1/17
     */
    public QueryResponseResult findTemplateList() {
        List<CmsTemplate> cmsTemplates = templateMongoDbDao.queryList(new CmsTemplate());
        QueryResult<CmsTemplate> queryResult = new QueryResult<>();
        queryResult.setList(cmsTemplates);
        return new QueryResponseResult(CommonCode.SUCCESS,queryResult);
    }

    /**
     * @Description 根据页面id查询页面
     * @author ShengJinFeng
     * @date 2020/1/17
     */
    public CmsPage queryCmsPageById(String pageId) {
        return cmsMongoDbDao.queryById(pageId);
    }

    /**
     * @Description 更新页面
     * @author ShengJinFeng
     * @date 2020/1/17
     */
    public CmsPageResult upate(CmsPage cmsPage) {
        CmsPage page = queryCmsPageById(cmsPage.getPageId());
        cmsMongoDbDao.updateFirst(page,cmsPage);
        return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
    }

    /**
     * @Description 删除页面
     * @author ShengJinFeng
     * @date 2020/1/17
     */
    public ResponseResult deletePage(String pageId) {
        CmsPage record = new CmsPage();
        record.setPageId(pageId);
        cmsMongoDbDao.delete(record);
        return new ResponseResult(CommonCode.SUCCESS);
    }

    /**
     * @Description 预览页面
     * @author ShengJinFeng
     * @date 2020/1/28
     */
    public String getPageHtml(String pageId){
        //获取页面模型数据集
        Map model = getModelByPageId(pageId);
        if (model == null){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        //获取页面模板
        String templateContent = getTemplateByPageId(pageId);
        if (StringUtils.isBlank(templateContent)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //执行静态化
        String html = generateHtml(templateContent,model);
        if (StringUtils.isBlank(html)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        return html;
    }

    /**
     * @Description 页面静态化
     * @author ShengJinFeng
     * @date 2020/1/28
     */
    private String generateHtml(String templateContent, Map model) {
        //生成配置类
        try {
            Configuration configuration = new Configuration(Configuration.getVersion());
            StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
            stringTemplateLoader.putTemplate("template",templateContent);
            configuration.setTemplateLoader(stringTemplateLoader);
            Template template1 = null;
            template1 = configuration.getTemplate("template");
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template1, model);
            return html;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Description 根据id获取模板信息
     * @author ShengJinFeng
     * @date 2020/1/28
     */
    private String getTemplateByPageId(String pageId) {
        //查询页面信息
        CmsPage cmsPage = queryCmsPageById(pageId);
        if (cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String templateId = cmsPage.getTemplateId();
        if (StringUtils.isBlank(templateId)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        CmsTemplate cmsTemplate = templateMongoDbDao.queryById(templateId);
        //获取模板文件id
        String templateFileId = cmsTemplate.getTemplateFileId();
        GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
        GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
        try {
            String content = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
            return content;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Description 获取页面模型数据
     * @author ShengJinFeng
     * @date 2020/1/30
     */
    private Map getModelByPageId(String pageId){
        CmsPage cmsPage = queryCmsPageById(pageId);
        if (cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String dataUrl = cmsPage.getDataUrl();
        if (StringUtils.isBlank(dataUrl)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        ResponseEntity<Map> forEntity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = forEntity.getBody();
        return body;
    }

    /**
     * @Description 发布页面
     * @author ShengJinFeng
     * @date 2020/1/30
     */
    public ResponseResult postPage(String pageId) {
        //执行静态话
        String pageHtml = getPageHtml(pageId);
        if (StringUtils.isBlank(pageHtml)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        //保存静态话页面到mongo中
        saveHtml(pageId,pageHtml);
        //发送消息
        sendMessage(pageId);
        return new ResponseResult(CommonCode.SUCCESS);
    }

    /**
     * @Description 保存成功后，发送消息
     * @author ShengJinFeng
     * @date 2020/1/30
     */
    private void sendMessage(String pageId) {
        Map<String,String> msgMap = new HashMap<>();
        msgMap.put("pageId",pageId);
        String msg = JSON.toJSONString(msgMap);
        //发送消息
        CmsPage cmsPage = cmsMongoDbDao.queryById(pageId);
        if (cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE,cmsPage.getSiteId(),msg);
    }

    /**
     * @Description 保存静态话页面到mongo中
     * @author ShengJinFeng
     * @date 2020/1/30
     */
    private CmsPage saveHtml(String pageId,String content){
        CmsPage cmsPage = cmsMongoDbDao.queryById(pageId);
        if (cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        //存储之前先删除
        String htmlFileId = cmsPage.getHtmlFileId();
        if (StringUtils.isNotBlank(htmlFileId)){
            gridFsTemplate.delete(Query.query(Criteria.where("_id").is(htmlFileId)));
        }
        //保存html文件到GridFS
        InputStream inputStream = IOUtils.toInputStream(content);
        ObjectId objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
        cmsPage.setHtmlFileId(objectId.toString());
        cmsMongoDbDao.save(cmsPage);
        return cmsPage;
    }

    /**
     * @Description 保存页面，存在时更新，没有时新增
     * @author ShengJinFeng
     * @date 2020/2/18
     */
    public CmsPageResult save(CmsPage cmsPage) {
        if (cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_ADDPAGE_INVALID);
        }
        CmsPage recode = new CmsPage();
        recode.setPageName(cmsPage.getPageName());
        recode.setSiteId(cmsPage.getSiteId());
        recode.setPageWebPath(cmsPage.getPageWebPath());
        //校验页面唯一性
        CmsPage page = cmsMongoDbDao.queryOne(recode);
        if (page != null){
            cmsPage.setPageId(page.getPageId());
            return upate(cmsPage);
        }else{
            return add(cmsPage);
        }
    }

    /**
     * @Description 一键发布页面
     * @author ShengJinFeng
     * @date 2020/2/19
     */
    public CmsPostPageResult postPageQuick(CmsPage cmsPage) {
        //保存页面，得到页面id
        CmsPageResult result = save(cmsPage);
        if (!result.isSuccess()){
            return new CmsPostPageResult(CommonCode.FAIL,null);
        }
        CmsPage page = result.getCmsPage();
        String pageId = page.getPageId();
        //发布页面，执行页面静态化，保存页面内容到mongo中，并向mq发消息
        ResponseResult responseResult = postPage(pageId);
        if (!responseResult.isSuccess()){
            return new CmsPostPageResult(CommonCode.FAIL,null);
        }
        //拼装页面的url
        String siteId = page.getSiteId();
        CmsSite cmsSite = siteMongoDbDao.queryById(siteId);
        String siteDomain = cmsSite.getSiteDomain();
        String siteWebPath = cmsSite.getSiteWebPath();
        String pageWebPath = page.getPageWebPath();
        String pageName = page.getPageName();
        String pageUrl = siteDomain+siteWebPath+pageWebPath+pageName;
        //返回结果
        return new CmsPostPageResult(CommonCode.SUCCESS,pageUrl);
    }
}
